package nio.demo;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * @Desc:   SocketChannel 案例
 * @author: cww
 * @DateTime: 2020-02-04 9:07
 */

public class SocketChannelDemo {
    public static void main(String[] args) throws Exception{
        // 打开 SocketChannel 方式
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("", 80));

        // 从 SocketChannel 读取数据
        ByteBuffer buf = ByteBuffer.allocate(48);
        // 同样表示读了多少字节进入 Buffer 里，如果返回 -1，表示已经读到流的末尾（连接关闭了）
        // 这个时候应该调用SocketChannel.close(),关闭channel；不然会不断执行read方法
        int bytesRead = socketChannel.read(buf);

        // 写入 SocketChannel
        String newData = "New String to write to file..." + System.currentTimeMillis();
        buf.put(newData.getBytes());
        buf.flip();
        // 注意SocketChannel.write()是在while循环中调用的。
        // 因为无法保证write()方法一次能向FileChannel写入多少字节，
        // 因此需要重复调用write()方法，直到Buffer中已经没有尚未写入通道的字节。
        while (buf.hasRemaining()) {
            socketChannel.write(buf);
        }

        socketChannel.close();
    }

    /**
     * 非阻塞模式该方法可能在连接建立之前就返回了。为了确定连接是否建立，可以调用finishConnect()的方法
     */
    public void nonBlocking() throws Exception{
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(new InetSocketAddress("", 80));
        while (!socketChannel.finishConnect()) {
            // 等待，或执行其他任务
        }
        // write() 非阻塞模式下，write()方法在尚未写出任何内容时可能就返回了。所以需要在循环中调用write()
        // read() 非阻塞模式下,read()方法在尚未读取到任何数据时可能就返回了。所以需要关注它的int返回值，它会告诉你读取了多少字节
    }

}
